#include "ET++.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "ChangeDialog.h"

#include "Class.h"
#include "FindChange_e.h"
#include "RegularExp.h"
#include "TextView.h"
#include "TextCmd.h"
#include "BorderItems.h"
#include "Fields.h"
#include "Buttons.h"
#include "Progress.h"
#include "CheapText.h"
#include "Box.h"
#include "Alert_e.h"
#include "String.h"

//---- ChangeDialog ------------------------------------------------------------

NewMetaImpl(ChangeDialog,FindDialog, (TP(scopecl)));

ChangeDialog::ChangeDialog(const char *title) : FindDialog(title)
{
}

VObject *ChangeDialog::DoMakeControls()
{
	return
		new VBox(10, eVObjHExpand,
			new Form(
				"Find:",   ei1= new TextField(cIdFind, 20),
				"Change:", ei2= new TextField(cIdChange, 20),
				0
			),
			new HBox(10, (VObjAlign)(eVObjVTop|eVObjHGapExpand),
				new BorderItem("Direction",
					modecl= new OneOfCluster(cIdFindMode,
						"Forward",
						"Backward",
						0
					)
				),
				new BorderItem("Options",
					optionscl= new ManyOfCluster(cIdFindOpt,
						"Ignore Case",
						"Match Whole Word",
						0
					)
				),
				new BorderItem("Change Scope",
					scopecl= new OneOfCluster(cIdChangeAllScope,
						"All of Document",
						"Selection Only",
						0
					)
				),
				0
			),
			0
		);
}

VObject *ChangeDialog::DoMakeActions()
{
	return
		new HBox(10, (VObjAlign)(eVObjVBase|eVObjHGapExpand),
			find= new ActionButton(cIdDoFind,           "Find Next", TRUE),
			change= new ActionButton(cIdDoChange,       "Change, Then Find"),
			changeAll= new ActionButton(cIdDoChangeAll, "Change All"),
			new ActionButton(cIdCancel,                 "Close"),
			0
		);
}

void ChangeDialog::DoSetup()
{
	FindDialog::DoSetup();
	bool b= ei1->GetTextSize() > 0;
	change->Enable(b);
	changeAll->Enable(b);
}

void ChangeDialog::Control(int id, int p, void *v)
{
	char b[100], b2[200];
	switch (id) {
	case cIdDoChange:
		ei1->GetString(b, 100);
		ei2->GetString(b2, 200);
		DoChange(b, b2);
		return;

	case cIdDoChangeAll:
		DoChangeAll(ei1->GetString(), ei2->GetString());
		return;
	}
	FindDialog::Control(id, p, v);
}

void ChangeDialog::DoChange(const char *what, const char *c)
{
	int from, to, f1, t1;

	tvp->GetSelection(&from, &to);
	bool forward= modecl->GetCurrentItem() == cIdForward;

	if (forward)
		tvp->SetSelection(from, from);
	else
		tvp->SetSelection(to, to);
	if (DoFind(what, forward)) {
		tvp->GetSelection(&f1, &t1);
		if (f1 == from && t1 == to) {
			tvp->GetSelection(&from, &to);
			tvp->PerformCommand(tvp->InsertString((byte*)c));
			if (!forward)
				tvp->SetSelection(from, from);
			DoFind(what, forward);
		}
	}
	tvp->RevealSelection();
}

void ChangeDialog::DoChangeAll(const char *find, const char *change)
{
	int from, to;
	tvp->GetSelection(&from, &to);
	if (scopecl->GetCurrentItem() == cIdChangeAll) {
		from= 0;
		to= tvp->GetText()->End();
	}
	int nChanges= ChangeAll(from, to, find, change);
	if (nChanges >= 0)
		ShowAlert(eAlertNote, "%d occurrences changed", nChanges);
}

int ChangeDialog::ChangeAll(int from, int to, const char *find, const char *change)
{
	int start= 0, n= 0, nChanges= 0;
	Text *tmp= tvp->GetText()->Save(from, to);
	if (!Compile(find))
		return -1;
	int changeTextLength= strlen(change);
	Text *changeText= tmp->MakeScratchText((byte*)change, changeTextLength);
	gProgress->Start("Searching", 100);
	for (int i= 0; ; i++) {
		start= tmp->Search(rex, &n, start);
		if (start == -1)
			break;
		tmp->ReplaceRange(start, start+n, changeText, 0, changeText->End());
		start+= changeTextLength;
		nChanges++;
		gProgress->Tick(i);
	}
	gProgress->Stop();

	if (nChanges) {
		tvp->SetSelection(from, to, FALSE);
		tvp->PerformCommand(new PasteTextCommand(tvp, tmp, cPASTE, "Change All"));
	}
	return nChanges;
}

